import os
import re
from ipaddress import IPv4Address
from pathlib import Path

import click
from flask.cli import with_appcontext

from app.models import Image, ImageType
from tools import db
from utils.utils import counter_time, init_opserver_conn
from utils.vthread import vthread

IMAGE_INFO = Path(__file__).parent / "lib/image.txt"


class NotFlavor:
    id = None

@vthread.pool(32)
def load_image(image, conn, image_list: list):
    image_name = image.name
    # 规则检查
    image_info = re.split("_", image_name)
    if len(image_info) < 4:
        return

    if image.visibility != "public":
        return

    image_info.append("")

    (
        status,
        img_name,
        img_type,
        flavor_size,
        ip,
        *args,
    ) = image_info  # TODO： 记得改镜像名中类型为container
    if status not in ImageType:
        return

    flavor = conn.compute.find_flavor(flavor_size)
    if not flavor:
        if image.container_format != "docker":
            print(
                f"[ERROR] The flavor `{flavor_size}` of the image `{image_name}` does not exist."
            )
            return
        else:
            flavor = NotFlavor
    print(f"已添加 {img_type:<20} 类型镜像：{image_name}")

    image_list.append(
        {
            "status": status,
            "image_name": img_name,
            "image_full_name": image_name,
            "image_id": image.id,
            "image_type": img_type,
            "flavor_id": flavor.id,
            "v4_fixed_ip": int(IPv4Address(ip)) if ip else None,
            "container_format": image.container_format,
            "tags": dict(
                val.split("=") for val in image["tags"] if re.match(r"(\S*)=(\S*)", val)
            ),
        }
    )


@counter_time
def read_write_image(image_names=None):
    """
    获取openstack配置
    """
    conn = init_opserver_conn()
    if os.path.isfile(IMAGE_INFO):
        os.remove(IMAGE_INFO)

    specify_images = []
    if image_names:
        specify_images = image_names.split(",")

    try:
        images = conn.image.images()
        # 镜像命名格式：镜像类型+镜像名+镜像类型+实例类型+内网ip, 以_分隔字段
        # 例子：	0_核电MIS_mis_4-4-80_192.168.2.100
        image_list = []
        if specify_images:
            images = [val for val in images if val.name in specify_images]

        for image in images:
            load_image(image, conn, image_list)

        vthread.pool.wait()

        try:
            with db.auto_commit():
                image_objs = [Image(**item) for item in image_list]
                db.session.bulk_save_objects(image_objs)
        except Exception as e:
            print("镜像导入失败")
            db.session.rollback()
            db.session.close()
            raise e
        else:
            # 更新image_name.txt, 配合operate_image脚本使用
            with IMAGE_INFO.open("a+", encoding="utf-8") as f:
                f.writelines(
                    f"{item['image_full_name']}:{item['image_id']}\n"
                    for item in image_list
                )
            print(f"共导入镜像：{len(image_list)} 个")

    except Exception as e:
        print(f"read_write_image error: {e}")
        return

    print("read_write_image success")


@click.command("init_image")
@click.option(
    "-n",
    "--image_names",
    default="",
    help="待添加镜像名称，名称以英文`,`隔开",
)
@with_appcontext
def init_image(image_names=None):
    """初始化镜像"""
    read_write_image(image_names=image_names)
